<template>
  <div class="list-search-wrapper">
    <div class="flex justify-between form-wrapper" ref="formWrapperRef">
      <div class="flex-1 form-content">
        <div class="cover-line" v-if="needHide" :style="'bottom:' + (toggleStatus ? '-32px;' : '-21px;')"></div>
        <template v-for="(row, arrIndex) in searchRows" :key="arrIndex">
          <div class="flex w-full form-row" v-show="arrIndex < 2 || toggleStatus">
            <template v-for="(item, index) in row" :key="index">
              <template v-if="item.label || item.childrens">
                <template v-if="item.type == 'search-group'">
                  <portal
                    v-model:model-value="searchFormData[item.prop]"
                    :search-item="item"
                    v-bind="item"
                    :labelWidthStyle="getFormLabelStyleFn(row, item, index)"
                    :contentWidthStyle="getFormContentStyleFn(row, item, index)"
                    @group-change="(...args) => portalGroupChangeFn(item, ...args)"
                    @press-enter="portalPressEnterChangeFn"
                    @change="portalChangeFn"
                  />
                </template>
                <template v-else>
                  <div class="form-item-label" :style="getFormLabelStyleFn(row, item, index)">{{ item.label }}</div>
                  <div class="form-item-content" :style="getFormContentStyleFn(row, item, index)">
                    <template v-if="!item.slot">
                      <!-- 分发到各个组件 -->
                      <portal
                        v-model.trim="searchFormData[item.prop]"
                        v-bind="item"
                        :search-item="item"
                        @clear="portalClearFn(item)"
                        @press-enter="(...args) => portalPressEnterChangeFn(item, ...args)"
                        @change="(...args) => portalChangeFn(item, ...args)"
                        @select="(...args) => portalSelectFn(item, ...args)"
                        @popup-visible-change="(...args) => popupVisibleChange(item, ...args)"
                      />
                    </template>
                    <template v-else>
                      <slot :name="item.slot" :searchForm="searchFormData"></slot>
                    </template>
                  </div>
                </template>
              </template>
              <template v-else>
                <div class="form-item-label" :style="getFormLabelStyleFn(row, item, index)"></div>
                <div class="form-item-content" :style="getFormContentStyleFn(row, item, index)"></div>
              </template>
            </template>
          </div>
        </template>
      </div>
      <div class="flex form-operate-content" ref="formOperateRef" :class="computedListLength ? 'form-operate-content-horizontal' : ''">
        <div class="splite-line" v-if="showButton"></div>
        <div class="form-operate-list" v-if="showButton">
          <a-button class="operate-button" type="primary" @click="searchFn" :loading="searchLoading">
            <template #icon><icon-search /></template>查询
          </a-button>
          <a-button class="operate-button" @click="resetFn" :loading="resetLoading">
            <template #icon><icon-refresh /></template>重置
          </a-button>
        </div>
        <div class="form-operate-list" v-if="!showButton"> <div class="operate-button"></div> </div>
      </div>
    </div>
    <a-divider
      class="custom-divider"
      :style="{ 'margin-top': toggleStatus ? '31px' : '0' }"
      orientation="center"
      v-if="searchRows.length > 2"
    >
      <div class="divider-content" @click="toggleStatus = !toggleStatus">
        {{ toggleStatus ? '收起筛选' : '展开筛选' }}
        <component class="divider-icon" :is="toggleStatus ? 'icon-up' : 'icon-down'" />
      </div>
    </a-divider>
    <a-divider class="custom-divider" v-else />
  </div>
</template>

<script setup>
  import { ref, computed, onMounted, onBeforeUnmount, getCurrentInstance, nextTick } from 'vue'
  import portal from './components/portal.vue'
  const { proxy } = getCurrentInstance()
  const Loading_Timeout = 1500

  const props = defineProps({
    searchForm: {
      type: Object,
      default() {
        return {}
      },
    },
    searchList: {
      type: Array,
      required: true,
      default() {
        return []
      },
    },
    columns: {
      type: [Number, String],
      default: 0,
    },
    showButton: {
      type: Boolean,
      default: true,
    },
    needHide: {
      type: Boolean,
      default: false,
    },
  })

  const isInModal = ref(false)

  // 动态列数计算 开始
  const calcLayoutSpanNumber = () => {
    if (props.columns) {
      return props.columns
    }

    // 计算当前window width
    const _width = window.innerWidth
    if (isInModal.value) {
      return 3
    } else {
      if (_width >= 1920) {
        return 4
      } else if (_width >= 1024 && _width < 1920) {
        return 3
      } else {
        return 2
      }
    }
  }

  /**
   * 在modal中，初始加载时，columns 为 0
   * 搜索框操作按钮宽度获取的是竖向的宽度，实际应该是横向的宽度
   * 导致在modal中，搜索框超出modal宽度
   */
  const columns = ref(calcLayoutSpanNumber())

  const computedListLength = computed(() => {
    return props.searchList.length <= columns.value
  })
  // 如果 props 参数存在 columns
  // 计算 content 宽度
  const formWrapperRef = ref()
  const formOperateRef = ref()
  const formContentWidth = ref()
  const calcContentWidth = () => {
    nextTick(() => {
      if (!formWrapperRef.value || !formOperateRef.value) return
      let totalWidth = formWrapperRef.value.offsetWidth
      let opeateWidth = formOperateRef.value.offsetWidth
      formContentWidth.value = totalWidth - opeateWidth
    })
  }

  // 监听容器变化
  let MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
  let observer = null
  let resizeObserver = null

  // 添加检测是否在 modal 中的逻辑
  onMounted(() => {
    // 检查父级组件中是否存在 a-modal
    const checkParentModal = (element) => {
      if (!element) return false
      if (element.classList?.contains('arco-modal')) return true
      return checkParentModal(element.parentElement)
    }

    nextTick(() => {
      isInModal.value = checkParentModal(formWrapperRef.value)
      calcContentWidth()

      // 初始化 MutationObserver
      if (formWrapperRef.value) {
        observer = new MutationObserver(calcContentWidth)
        observer.observe(formWrapperRef.value, {
          attributes: true,
          attributeFilter: ['style', 'class'],
          subtree: true,
        })

        // 添加ResizeObserver监听父元素尺寸变化
        resizeObserver = new ResizeObserver(calcContentWidth)
        resizeObserver.observe(formWrapperRef.value.parentElement)
      }

      window.addEventListener('resize', calcContentWidth)

      if (!props.columns) {
        columns.value = calcLayoutSpanNumber()
        window.addEventListener('resize', () => {
          columns.value = calcLayoutSpanNumber()
        })
      }
    })
  })

  onBeforeUnmount(() => {
    if (observer) {
      observer.disconnect()
      observer = null
    }

    if (resizeObserver) {
      resizeObserver.disconnect()
      resizeObserver = null
    }

    window.removeEventListener('resize', calcContentWidth)
    if (!props.columns) {
      window.removeEventListener('resize', () => {
        columns.value = calcLayoutSpanNumber()
      })
    }
  })
  // 动态列数计算 结束

  // 计算 searchRows
  const searchRows = computed(() => {
    const list = props.searchList
    let rows = [{ span: 0, arr: [] }]
    let columnsValue = columns.value
    if (columnsValue == 0) {
      return []
    }
    for (let i = 0; i < list.length; i++) {
      let item = list[i]
      let itemSpan = item.span || 1
      let lastRow = rows[rows.length - 1]
      // 将当前 item 放入一行内是否会超限
      if (lastRow.span + itemSpan <= columnsValue) {
        lastRow.arr.push(item)
        lastRow.span += itemSpan
      } else {
        // if (itemSpan == 2 && columnsValue == 3) {
        // lastRow.arr.push({})
        // lastRow.span += 1
        // i--
        // console.log(lastRow)
        // } else {
        rows.push({ span: itemSpan, arr: [item] })
        // }
      }
    }
    // 补足最后一行数据
    let lastRow = rows[rows.length - 1]
    if (lastRow.span != columnsValue) {
      let diff = columnsValue - lastRow.span
      while (diff > 0) {
        lastRow.arr.push({})
        diff--
      }
    }
    return rows.map((item) => {
      return item.arr
    })
  })

  // 列宽数组
  const labelWidthList = computed(() => {
    // 计算每一列的宽度
    let rows = searchRows.value
    const textLenMaxNum = [0, 0, 0, 0]
    rows.forEach((row) => {
      row.forEach((col, colIndex) => {
        const { label, childrens } = col

        let labelLen = label?.length || 0
        // search-group 取 gorup 中的最长值
        if (labelLen == 0 && childrens) {
          let maxLen = 0
          childrens.forEach((op) => {
            let len = op.label?.length || 0
            if (len > maxLen) maxLen = len
          })
          labelLen = maxLen + 2 // +2 预留出select ↓ icon宽度
        }
        // 第二列或第三列
        if (colIndex == 1 || colIndex == 2) {
          const prvCol = row[colIndex - 1]
          // 如果前一个 col span为2，此时情况为
          // 三列布局，第一个输入项占两列
          if (prvCol?.span == 2) {
            colIndex = colIndex + 1
          }
        }
        textLenMaxNum[colIndex] < labelLen ? (textLenMaxNum[colIndex] = labelLen) : ''
      })
    })
    // <= 3 个字 80
    // 4 个字 100
    // 5-6 个字 120
    // >= 7 个字 140
    const _widthList = textLenMaxNum.map((num) => {
      if (num <= 3) return 80
      if (num == 4) return 100
      if (num == 5 || num == 6) return 120
      if (num >= 7) return 140
    })
    return _widthList
  })
  // 计算 formLabelStyle
  const getFormLabelStyleFn = (row, item, index) => {
    // 判断当前 item 所处的位置，index 不太准确
    // 因为当三列的情况下，可能存在如下的情况：
    // label conte...............t label content
    // label content label content label content
    // 当前是三列还是两列
    let columnsValue = columns.value
    let pos = index
    if (index >= 1 && columnsValue == 3) {
      // 如果上一项 span == 2 则为标准三列布局
      if (row[index - 1].span == 2) {
        pos = 2
      }
    }
    return {
      width: labelWidthList.value[pos] + 'px',
    }
  }
  // 计算 formContentStyle
  const getFormContentStyleFn = (row, item, index) => {
    // 总列数
    let columnsValue = columns.value
    // label 总宽度
    let sumWidth = 0
    let labelWidthListValue = labelWidthList.value
    labelWidthListValue.slice(0, columnsValue).forEach((width) => (sumWidth += width))
    let styleWidth = ''
    if (columnsValue == 4) {
      // 判断当前行存不存在 span:2
      if (row.filter((item) => item.span == 2)) {
        let span = item.span || 1
        if (span == 2) {
          if (index == 0) {
            styleWidth = `calc(calc(100% - ${sumWidth}px) / 4 * 2 + ${labelWidthListValue[1]}px)`
          } else if (index == 1) {
            styleWidth = `calc(calc(100% - ${sumWidth}px) / 4 * 2 + ${labelWidthListValue[2]}px)`
          } else if (index == 2) {
            styleWidth = `calc(calc(100% - ${sumWidth}px) / 4 * 2 + ${labelWidthListValue[3]}px)`
          }
        } else {
          styleWidth = `calc(calc(100% - ${sumWidth}px) / 4 )`
        }
      } else {
        styleWidth = `calc(calc(100% - ${sumWidth}px) / 4 )`
      }
    } else if (columnsValue == 3) {
      // 判断当前行存不存在 span:2
      if (row.filter((item) => item.span == 2)) {
        let span = item.span || 1
        if (span == 2) {
          if (index == 0) {
            styleWidth = `calc(calc(100% - ${sumWidth}px) / 3 * 2 + ${labelWidthListValue[1]}px)`
          } else {
            styleWidth = `calc(calc(100% - ${sumWidth}px) / 3 * 2 + ${labelWidthListValue[2]}px)`
          }
        } else {
          styleWidth = `calc(calc(100% - ${sumWidth}px) / 3 )`
        }
      } else {
        styleWidth = `calc(calc(100% - ${sumWidth}px) / 3 )`
      }
    } else {
      let span = item.span || 1
      if (span == 2) {
        styleWidth = `calc(calc(100% - ${sumWidth}px) + ${labelWidthListValue[1]}px)`
      } else {
        styleWidth = `calc(calc(100% - ${sumWidth}px) / 2`
      }
    }
    if (formContentWidth.value) {
      styleWidth = styleWidth.replace('100%', formContentWidth.value + 'px')
    }
    return {
      width: styleWidth,
    }
  }
  // 展开收起 start
  const toggleStatus = ref(false) // true 打开状态 false 关闭状态
  // 展开收起 end
  const emit = defineEmits(['update:searchForm', 'loadData', 'change', 'reset', 'submit', 'popup-visible-change', 'select'])
  const searchFormData = computed({
    get() {
      return props.searchForm
    },
    set(val) {
      emit('update:searchForm', val)
    },
  })
  // 重置
  const defaultFormVal = JSON.parse(JSON.stringify(props.searchForm))
  const resetLoading = ref(false)
  const resetFn = async () => {
    // loading
    resetLoading.value = true
    setTimeout(() => {
      resetLoading.value = false
    }, Loading_Timeout)
    // 先reset再掉接口；防止调用接口参数错误
    emit('reset')
    props.searchList.forEach((item) => {
      let prop = item.prop
      searchFormData.value[prop] = defaultFormVal[prop]
      let changeV = item.change
      if (changeV && typeof changeV == 'function') {
        changeV(defaultFormVal[prop])
      }
      let childrens = item.childrens
      if (childrens && childrens.length > 0) {
        let childOption = childrens.find((childItem) => childItem.prop == item.prop)
        let childChanegV = childOption.change
        if (childChanegV && typeof childChanegV == 'function') {
          childChanegV(defaultFormVal[prop])
        }
      }
    })
    emit('loadData', 1, 'reset')
    // emit('reset')
  }
  // 查询
  const searchLoading = ref(false)
  const searchFn = () => {
    emit('loadData', 1, 'submit')
    emit('submit')
    searchLoading.value = true
    setTimeout(() => {
      searchLoading.value = false
    }, Loading_Timeout)
  }
  // 子组件 group change 函数
  // currSelect 为searchItem选中的值
  // prevSelect 为searchItem之前选中的值
  const portalGroupChangeFn = (searchItem, currSelect, prevSelect) => {
    // 记录之前选中的 prop 对应的 value
    const prevSelectValue = searchFormData.value[prevSelect]
    // 1 设置 prevSelect 对应的 value
    let setPrevValue = undefined
    searchFormData.value[prevSelect] = setPrevValue
    let prevSelectChildItem = searchItem.childrens.find((child) => child.prop == prevSelect)
    let changeV = prevSelectChildItem.change
    if (changeV && typeof changeV == 'function') {
      changeV(setPrevValue)
    }
    // 2 设置 currSelect 对应的 value
    // 如果 keepValueOnChange 为 true 则需要保留之前的值
    if (searchItem.keepValueOnChange) {
      searchFormData.value[currSelect] = prevSelectValue
      let currSelectChildItem = searchItem.childrens.find((child) => child.prop == currSelect)
      let changeV2 = currSelectChildItem.change
      if (changeV2 && typeof changeV2 == 'function') {
        changeV2(prevSelectValue)
      }
    }
    // 清空当前 activeItem modelValue 结束
    // 触发 searchGroup change
    searchItem.change && searchItem.change(currSelect, prevSelect)
    proxy.$forceUpdate()
  }
  // 子组件change传递函数
  const portalChangeFn = (item, a, b, c) => {
    emit('change', item, a, b, c)
    item.change && item.change(a, b, c)
  }
  const portalSelectFn = (item, a, b, c) => {
    emit('select', item, a, b, c)
    item.select && item.select(a, b, c)
  }
  const popupVisibleChange = (item, val) => {
    emit('popup-visible-change', item, val)
    item.popupVisibleChange && item.popupVisibleChange(val)
  }
  // 子组件 clear
  const portalClearFn = (item) => {
    searchFormData.value[item.prop] = undefined
  }
  // 组件回车事件
  const portalPressEnterChangeFn = (item, a, b, c) => {
    if (item.type == 'a-input' || item.type == 'i-input') {
      emit('loadData', 1, 'inputChange')
      emit('change', item, a, b, c)
      item.change && item.change(a, b, c)
    }
  }

  // 重置搜索组
  const resetSearchGroup = () => {
    props.searchList.forEach((item) => {
      if (item.type == 'search-group') {
        item.prop = item.childrens[0].prop
      }
    })

    // 强制更新
    proxy.$forceUpdate()
  }

  defineExpose({
    resetSearchGroup,
  })
</script>

<style lang="less" scoped>
  .list-search-wrapper {
    .form-wrapper {
      display: flex;
      margin-bottom: 20px;
      position: relative;
      .cover-line {
        position: absolute;
        width: 120px;
        height: 2px;
        background: #ffffff;
        right: 0;
        z-index: 1;
      }
      .form-operate-content {
        padding-left: 20px;
        .splite-line {
          width: 1px;
          height: 80px;
          background-color: var(--color-neutral-3);
        }
        .form-operate-list {
          margin-left: 20px;
          width: 80px;

          .operate-button + .operate-button {
            margin-top: 16px;
          }
        }
      }
      .form-operate-content-horizontal {
        .splite-line {
          display: none;
        }
        .form-operate-list {
          margin-left: 0;
          width: 181px;
          .operate-button {
            float: right;
          }
          .operate-button + .operate-button {
            margin-top: 0;
            margin-right: 16px;
          }
        }
      }
      .form-row {
        margin-bottom: 17px;
        .form-item-label {
          text-align: right;
          padding-right: 16px;
          padding-top: 6px;
          line-height: 1.24;
          font-size: 14px;
          color: var(--color-text-2);
        }
      }
      .form-row:last-child {
        margin-bottom: 0;
      }
    }

    .divider-content {
      cursor: pointer;
      font-size: 14px;
      user-select: none;
      color: rgb(var(--primary-6));

      .divider-icon {
        margin-left: 8px;
      }
    }
    .custom-divider {
      margin: 0 0 20px;
    }
  }
</style>
